package cn.xxm.ff.log.core.service;

import cn.xxm.ff.log.common.utils.DesensitizationHelper;
import cn.xxm.ff.log.common.utils.PropertyUtil;
import cn.xxm.ff.log.core.dto.CustomDesensitizeType;
import cn.xxm.ff.log.core.service.DesensitizationPolicy;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Type;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by WUHONGTAO627 on 2018-08-22.
 */
public class DesensitizationPolicyJsonImprovementImpl implements DesensitizationPolicy {
    @Override
    public Object[] desensitizeArgs(Object[] objs, Map<String, Set<String>> map, boolean stringKillSwitch) {
        return warpMessageArgs(objs, map, stringKillSwitch);
    }

    @Override
    public String desensitizeFormattedMessage(String formattedMinMessage, Map<String, Set<String>> map){
        int beginObjectIndex = formattedMinMessage.indexOf("{");
        int endObjectIndex = formattedMinMessage.lastIndexOf("}");

        int beginListIndex = formattedMinMessage.indexOf("[");
        int endListIndex = formattedMinMessage.lastIndexOf("]");

        int beginIndex = (beginObjectIndex < beginListIndex) || beginListIndex == -1 ? beginObjectIndex : beginListIndex ;

        int endIndex = (endObjectIndex > endListIndex ) ? endObjectIndex : endListIndex;


        String substring = DesensitizationHelper.preHandleJsonString(formattedMinMessage, beginIndex, endIndex);
        JSONObject json = null;
        if(beginIndex == beginObjectIndex){
            json = JSONObject.parseObject(substring);
            // 脱敏
            for (CustomDesensitizeType type: PropertyUtil.getTypeRetain().values()) {
                desensitizeMessage(json, type, map);
            }
            formattedMinMessage = new StringBuilder(formattedMinMessage)
                    .replace(beginIndex, endIndex + 1,
                            json.toJSONString()).toString();
        }else {
            //List<Object> mapList = JacksonUtil.jsonToList(substring, Object.class);
            JSONArray mapList = JSONObject.parseArray(substring);
            operationListParam(mapList,map);
            formattedMinMessage = new StringBuilder(formattedMinMessage)
                    .replace(beginIndex, endIndex + 1,
                            JSONObject.toJSONString(mapList)).toString();
        }
        return formattedMinMessage;
    }


    private void operationListParam(List<Object> mapList,Map<String, Set<String>> map){
        for (Object object : mapList) {
            if(object instanceof JSONObject){
                // 脱敏
                for (CustomDesensitizeType type: PropertyUtil.getTypeRetain().values()) {
                    desensitizeMessage((JSONObject) object, type, map);
                }
            }else if(object instanceof List){
                // 递归调用,直到最底层没有list
                operationListParam((List<Object>) object,map);
            }
        }
    }


    /**
     * 对日志参数脱敏
     *
     * @param args
     * @return
     */

    private Object[] warpMessageArgs(Object[] args, Map<String, Set<String>> map, boolean stringKillSwitch) {

        Object[] result = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            Object o = args[i];
            JSONObject json = null;
            // 对string做json转换
            try {
                if (o instanceof String) {
                    json = JSONObject.parseObject(DesensitizationHelper.handleStringBeforeParse((String) o));
                } else if (o instanceof JSONObject) {
                    json = JSONObject.parseObject(DesensitizationHelper.handleStringBeforeParse(JSONObject.toJSONString(o)));
                } else if (o instanceof Map) {
                    String jsonStr = JSONObject.toJSONString(o);
                    json = JSONObject.parseObject(jsonStr);
                } else {
                    String jsonStr = JSONObject.toJSONString(o);
                    json = JSONObject.parseObject(jsonStr);
                }
            } catch (Exception e) {
                if (stringKillSwitch) {
                    result[i] = "************";
                } else {
                    result[i] = o;
                }
                continue;
            }
            if (json != null) {
                // 脱敏
                for (CustomDesensitizeType type: PropertyUtil.getTypeRetain().values()) {
                    desensitizeMessage(json, type, map);
                }

            }
            result[i] = json;
        }
        return result;
    }

    private static void desensitizeMessage(JSONObject json, CustomDesensitizeType type,
                                           Map<String, Set<String>> map) {
        // 检查
        if (json == null || map == null || map.isEmpty()) {
            return;
        }

        // 检查脱敏字段
        Set<String> keyFields = map.get(type.getType());
        if (keyFields == null || keyFields.isEmpty()) {
            return;
        }

        if (keyFields.size() < json.keySet().size()) {
            desensitizeMessageLoopByKeyField(json, type, map);
        } else {
            desensitizeMessageLoopByJsonField(json, type, map);
        }

    }

    private static void desensitizeMessageLoopByJsonField(JSONObject json,
                                                          CustomDesensitizeType type,
                                                          Map<String, Set<String>> map) {
        // 要脱敏的关键字
        Set<String> keyFields = map.get(type.getType());

        // 处理
        List<JSONObject> innerJsonObjects = new ArrayList<>(0);

        // 处理第一层非JSONObject
        for (String field: json.keySet() ) {

            Object v = json.get(field);
            if (v == null || v instanceof JSONObject) {
                innerJsonObjects.add((JSONObject)v);
                continue;
            } else if (v instanceof JSONArray) {
                addJsonArrayToInnerJsonObjects(innerJsonObjects, (JSONArray) v);
            }

            // 不需要脱敏的关键字，直接返回
            if (!keyFields.contains(field)) {
                continue;
            }

            // 脱敏处理JSONArray和String
            desensitizeValue(json, type, field, v);
        }

        // 处理嵌套层的JSONObject
        for (JSONObject ijObj: innerJsonObjects) {
            desensitizeMessage(ijObj, type, map);
        }
    }

    private static void desensitizeValue(JSONObject json,
                                         CustomDesensitizeType type,
                                         String field, Object v) {
        if (v instanceof JSONArray) {
            desensitizeJsonArray(json, type, field, (JSONArray) v);
        } else {
            String newVal = DesensitizationHelper.processNumberValue((String)v, type);
            json.put(field, newVal);
        }
    }

    private static void addJsonArrayToInnerJsonObjects(List<JSONObject> innerJsonObjects, JSONArray v) {
        for (Object o: v) {
            if(o instanceof JSONObject) {
                innerJsonObjects.add((JSONObject) o);
            }
        }
    }

    private static void desensitizeJsonArray(JSONObject json, CustomDesensitizeType type, String field, JSONArray v) {
        JSONArray newArray = new JSONArray();
        for (Object o: v) {
            if (o instanceof String) {
                String newVal = DesensitizationHelper.processNumberValue((String) o, type);
                newArray.add(newVal);
            }
        }

        if (!newArray.isEmpty()) {
            json.put(field, newArray);
        }
    }

    private static void desensitizeMessageLoopByKeyField(JSONObject json, CustomDesensitizeType type,
                                                         Map<String, Set<String>> map) {
        // 脱敏字段
        Set<String> fields = map.get(type.getType());

        // 处理第一层非JSONObject
        for (String field: fields ) {
            Object v = json.get(field);
            if (v == null || v instanceof JSONObject) {
                continue;
            }

            // 脱敏处理JSONArray和String
            desensitizeValue(json, type, field, v);
        }

        // 非值为JSONObject的处理
        // 处理
        List<JSONObject> innerJsonObjects = new ArrayList<>(0);
        for (String k: json.keySet()) {
            Object v = json.get(k);

            if (v instanceof JSONObject) {
                innerJsonObjects.add((JSONObject)v);
            } else if (v instanceof JSONArray) {
                addJsonArrayToInnerJsonObjects(innerJsonObjects, (JSONArray) v);
            }
        }

        // 处理嵌套层的JSONObject
        for (JSONObject ijObj: innerJsonObjects) {
            desensitizeMessage(ijObj, type, map);
        }
    }

}
